﻿/*
 * Copyright 2011 Hanns Kucer
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Text;

namespace iTachToolkit
{
    public class IR
    {
        private readonly string[] parts;
        public readonly int Id;

        public class BurstPair
        {
            public readonly int On;
            public readonly int Off;
            internal BurstPair(int on, int off)
            {
                On = on;
                Off = off;
            }
        }
        public BurstPair this[int index]
        {
            get
            {
                index = 6 + 2 * index;
                return new BurstPair(int.Parse(parts[index]), int.Parse(parts[index + 1]));
            }
        }

        public int Frequency
        {
            get
            {
                return int.Parse(parts[3]);
            }
        }

        public int Repeat
        {
            get
            {
                return int.Parse(parts[4]);
            }
        }

        public int Offset
        {
            get
            {
                return int.Parse(parts[5]);
            }
        }

        // sendir,<module:connector>,<ID>,<frequency>,<repeat>,<offset>,<on1>,<off1>,<on2>,<off2>,….,<onN>,<offN>
        internal IR(string[] parts)
        {
            this.Id = int.Parse(parts[2]);
            this.parts = parts;
        }

        public IR(string gc_ir) : this(gc_ir.Split(','))
        {
        }

        public IR(string hex_ir, int connector, int id) : this(Hex2Gc(hex_ir, connector, id))
        {
        }

        public IR(ushort[] hex_ir, int offset, int length, int connector, int id) : this(Hex2Gc(hex_ir, offset, length, connector, id))
        {
        }

        // Översätter från CCF (Pronto hex) till GC
        // Se http://www.hifi-remote.com/infrared/IR-PWM.shtml
        private static string Hex2Gc(string hex_ir, int connector, int id)
        {
            string[] h = hex_ir.Trim().Split(' ');

            var str = new StringBuilder();

            if (h[0] != "0000")
                throw new Exception("Invalid HEX sequence!");

            double N = int.Parse(h[1], System.Globalization.NumberStyles.HexNumber);
            int freq = (int)(1000000.0 / (N * 0.241246));
            //			int freq = (int) (4145146.4480240086882269550583222 / N);

            // # of burst pairs (i.e. on/off-pairs) in preamable 
            int bp_s1 = int.Parse(h[2], System.Globalization.NumberStyles.HexNumber);
            // # of burst pairs in sequence
            int bp_s2 = int.Parse(h[3], System.Globalization.NumberStyles.HexNumber);

            int offset = bp_s1 + 1;

            str.Append("sendir,1:"); // module always 1 for iTach devices
            str.Append(connector);
            str.Append(",");
            str.Append(id);
            str.Append(",");
            str.Append(freq);
            str.Append(",2"); // # repetitions (always twice)
            str.Append(",");
            str.Append(offset);

            for (int i = 4; i < h.Length; i++)
            {
                str.Append(",");
                str.Append(int.Parse(h[i], System.Globalization.NumberStyles.HexNumber));
            }

            return str.ToString();
        }

        private static string Hex2Gc(ushort[] hex_ir, int offset, int length, int connector, int id)
        {
            var hex = new StringBuilder();

            length--;

            for (int i = 0; true; i++)
            {
                hex.Append(hex_ir[offset + i].ToString("X4"));
                if (i == length) break;
                hex.Append(" ");
            }

            return Hex2Gc(hex.ToString(), connector, id);
        }

        /// <summary>
        /// Number of IR on/off values (burst pairs)
        /// </summary>
        public int Length
        {
            get
            {
                return (parts.Length - 6) / 2;
            }
        }

        public enum StringFormat
        {
            /// <summary>
            /// Full Gc sendir command
            /// </summary>
            Gc = 1,
            /// <summary>
            /// Stripped Gc ir command
            /// </summary>
            StrippedGc = 2,
            /// <summary>
            /// Hex, i.e. CCF or "Pronto Hex"
            /// </summary>
            Hex = 3
        }

        /// <summary>
        /// Returns a stripped Gc ir command string
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return string.Join(",", parts, 3, parts.Length - 3);
        }

        public string ToString(StringFormat fmt)
        {
            switch (fmt)
            {
                case StringFormat.Gc:
                    return string.Join(",", parts);
                case StringFormat.StrippedGc:
                    return ToString();
                case StringFormat.Hex:
                    break;
            }

            var s = new StringBuilder();

            int f = (int)(4145146.4480240086882269550583222 / (double)Frequency);

            s.Append("0000 ");
            s.Append(f.ToString("X4"));
            s.Append(" ");
            s.Append((Offset - 1).ToString("X4"));
            s.Append(" ");
            s.Append((Length).ToString("X4"));

            for (int i = 0; i < Length; i++)
            {
                var bp = this[i];
                s.Append(" ");
                s.Append(bp.On.ToString("X4"));
                s.Append(" ");
                s.Append(bp.Off.ToString("X4"));
            }

            return s.ToString();
        }
    }

}
